package com.sky.loveshop.config;

import feign.FeignException;
import feign.Response;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

/**
 * @author xcy
 * @version V1.0
 * @description 使用自定义的解码器对其他解码器进行再次包装，目的：为了打印出feign调用第三方接口返回的原始报文数据，
 * 方便排查到底为什么序列化成我方定义的对象时会报错
 * @date 2024/11/9 18:00
 */
@Slf4j
public class LoggingDecoder implements Decoder {

    private final Decoder delegate;

    public LoggingDecoder(Decoder delegate) {
        this.delegate = delegate;
    }

    @Override
    public Object decode(Response response, Type type) throws IOException, FeignException {
        // 读取原始响应体
        String rawResponseBody = readResponseBody(response);
        // 打印原始响应体
        log.info("FeignRequest Raw Response 响应 Body: {}", rawResponseBody);

        /*
        问题：我自己在定义一个当前decoder类进行对原始返回报文的输出，但是发现后续进行json序列化成自定义的返回值对象中没有值了，返回取值为null，数据怎么丢失了？
        1. 确保响应体能被正确读取
        在自定义Decoder中，你需要确保你在读取响应体后，正确地维护了流的状态。如果你在读取流时消耗掉了响应体的内容，而后续解析时又试图多次读取它，就会导致null或错误。

        2. 使用Response的副本
        Response对象的流只能读取一次。所以在读取数据并打印后，如果没有正确地将流重置，后续的Decoder会因为流已经被消耗而失败。你可以创建一个Response的副本来避免这个问题。
         */

        // 需要创建一个新的Response对象，以便后续解码器可以读取原始内容
        Response copyResponse = Response.builder()
                .status(response.status())
                .reason(response.reason())
                .headers(response.headers())
                .body(rawResponseBody, StandardCharsets.UTF_8)
                .request(response.request())
                .build();

        // 继续使用委托的Decoder进行实际解码
        return delegate.decode(copyResponse, type);
    }

    private String readResponseBody(Response response) throws IOException {
        // 转换InputStream为String
        BufferedReader reader = new BufferedReader(new InputStreamReader(response.body().asInputStream()));
        return reader.lines().collect(Collectors.joining("\n"));
    }
}
